/*
 * REFServiceRegistry.h
 *
 *  Created on: Jun 18, 2013
 *      Author: Lucifer
 */

#ifndef REFSERVICEREGISTRY_H_
#define REFSERVICEREGISTRY_H_

namespace BFX
{

class REFEventDispatcher;

////////////////////////////////////////////////////////////////////////////////

/**
 * The base class of all event service objects.
 */
class REFService : public REFObject
{
public:
	/**
	 * Initializes a new instance of BFX::REFService.
	 * @param pDispatcher The event dispatcher own to.
	 * @param id The service id.
	 */
	REFService(REFEventDispatcher*	pDispatcher, long id)
		: m_pDispatcher(pDispatcher), m_id(id)
	{
	}
	virtual ~REFService()
	{
		Shutdown();
	}

	/**
	 * Gets the service id.
	 */
	long GetServiceId() const
	{
		return m_id;
	}

	/**
	 * Shutdown the service. the derived class will override this method to customizes shutdown operations.
	 */
	virtual void Shutdown() {}

private:
	friend class REFServiceRegistry;
	REF<REFService>	m_pNext;			// Pointer to the next service in the linked list.
	REFEventDispatcher*	m_pDispatcher;	// The own event dispatcher.
	long	m_id;						// The service's id.
};

////////////////////////////////////////////////////////////////////////////////

/**
 * Represents a base class of event service objects have the ability to generate the service id automatically.
 */
template<typename T>
class REFServiceBase : public REFService
{
public:
	/**
	 * Initializes a new instance of BFX::REFServiceBase.
	 * @param pDispatcher The event dispatcher own to.
	 */
	REFServiceBase(REFEventDispatcher* pDispatcher)
		: REFService(pDispatcher, ServiceId())
	{
	}

	/**
	 * Gets the auto-generated service id.
	 * @return The service id.
	 */
	static long ServiceId()
	{
		// use the static object's address to be the unique id.
		static struct dummy {} s_dummy;
		return (long)&s_dummy;
	}
};

////////////////////////////////////////////////////////////////////////////////

/**
 * Provides a registry to manage a group of event services.
 */
class REFServiceRegistry : public REFObject
{
public:
	/**
	 * Initializes a new instance of BFX::REFServiceRegistry.
	 * @param pDispatcher The event dispatcher own to.
	 */
	REFServiceRegistry(REFEventDispatcher* pDispatcher)
	{
		BFX_ASSERT(pDispatcher != NULL);
		m_pDispatcher = pDispatcher;
	}

	/**
	 * Destroys the BFX::REFServiceRegistry instance.
	 */
	virtual ~REFServiceRegistry()
	{
		MutexHolder lock(&m_mutex);

		// shutdown and releases all services recursively.
		m_pFirst = NULL;
	}

	/**
	 * Gets the instance by specified service type, or create a new instance if not exists.
	 * @return The instance of specified service type.
	 */
	template<typename T>
	T* CreateOrGetService()
	{
		MutexHolder lock(&m_mutex);

		// first, lookup if there is an existing service object with the given key.
		long id = T::ServiceId();
		REFService* pService = m_pFirst;
		while (pService)
		{
			if (pService->GetServiceId() == id)
				return (T*) pService;
			pService = pService->m_pNext;
		}

		// create a new service object.
		REF<T> pNewService = new T(m_pDispatcher);

		// service was successfully initialized, pass ownership to registry.
		pNewService->m_pNext = m_pFirst;
		m_pFirst = pNewService;

		return (T*) pNewService;
	}

private:
	Mutex	m_mutex;					// The concurrent lock object.
	REF<REFService>	m_pFirst;			// Pointer to the first service in the linked list.
	REFEventDispatcher*	m_pDispatcher;	// The own event dispatcher.
};

} /* namespace BFX */
#endif /* REFSERVICEREGISTRY_H_ */
